import { exec, spawn } from 'child_process';
import { promisify } from 'util';
import * as path from 'path';
import * as fs from 'fs';
import * as os from 'os';
import * as https from 'https';
import { pipeline } from 'stream';
import { createWriteStream } from 'fs';
import { app } from 'electron';

const execAsync = promisify(exec);
const pipelineAsync = promisify(pipeline);

export interface NodeEnvironmentStatus {
  isInstalled: boolean;
  version?: string;
  npmVersion?: string;
  installPath?: string;
  isPortable?: boolean;
  error?: string;
}

export interface NodeInstallProgress {
  stage: 'downloading' | 'extracting' | 'configuring' | 'completed' | 'error';
  progress: number;
  message: string;
  error?: string;
}

export class NodeEnvironmentService {
  private static instance: NodeEnvironmentService;
  private nodePortablePath: string;
  private downloadUrl: string;
  
  constructor() {
    // 设置便携版Node.js的安装路径（用户目录下，无需管理员权限）
    this.nodePortablePath = path.join(os.homedir(), '.automation-tools', 'nodejs');
    // 使用Node.js官方的便携版下载链接（Windows x64）
    this.downloadUrl = 'http://10.169.128.20/files/python/node-v20.13.0-win-x64.zip';
  }

  public static getInstance(): NodeEnvironmentService {
    if (!NodeEnvironmentService.instance) {
      NodeEnvironmentService.instance = new NodeEnvironmentService();
    }
    return NodeEnvironmentService.instance;
  }

  /**
   * 检查Node.js环境状态
   */
  public async checkNodeEnvironment(): Promise<NodeEnvironmentStatus> {
    try {
      // 首先检查系统是否已安装Node.js
      const systemNodeStatus = await this.checkSystemNode();
      if (systemNodeStatus.isInstalled) {
        return systemNodeStatus;
      }

      // 检查便携版Node.js
      const portableNodeStatus = await this.checkPortableNode();
      return portableNodeStatus;
    } catch (error: any) {
      return {
        isInstalled: false,
        error: `检查Node.js环境时出错: ${error.message}`
      };
    }
  }

  /**
   * 检查系统安装的Node.js
   */
  private async checkSystemNode(): Promise<NodeEnvironmentStatus> {
    try {
      const { stdout: nodeVersion } = await execAsync('node --version');
      const { stdout: npmVersion } = await execAsync('npm --version');
      const { stdout: wherePath } = await execAsync('where node');
      
      return {
        isInstalled: true,
        version: nodeVersion.trim(),
        npmVersion: npmVersion.trim(),
        installPath: wherePath.trim().split('\n')[0],
        isPortable: false
      };
    } catch (error) {
      return {
        isInstalled: false,
        error: 'Node.js未在系统PATH中找到'
      };
    }
  }

  /**
   * 检查便携版Node.js
   */
  private async checkPortableNode(): Promise<NodeEnvironmentStatus> {
    try {
      const nodeExePath = path.join(this.nodePortablePath, 'node.exe');
      const npmPath = path.join(this.nodePortablePath, 'npm.cmd');
      
      if (!fs.existsSync(nodeExePath)) {
        return {
          isInstalled: false,
          error: '便携版Node.js未安装'
        };
      }

      const { stdout: nodeVersion } = await execAsync(`"${nodeExePath}" --version`);
      let npmVersion = 'N/A';
      
      try {
        const { stdout: npm } = await execAsync(`"${npmPath}" --version`);
        npmVersion = npm.trim();
      } catch (npmError) {
        console.warn('无法获取npm版本:', npmError);
      }
      
      return {
        isInstalled: true,
        version: nodeVersion.trim(),
        npmVersion: npmVersion,
        installPath: this.nodePortablePath,
        isPortable: true
      };
    } catch (error: any) {
      return {
        isInstalled: false,
        error: `检查便携版Node.js时出错: ${error.message}`
      };
    }
  }

  /**
   * 安装便携版Node.js（无需管理员权限）
   */
  public async installPortableNode(
    progressCallback?: (progress: NodeInstallProgress) => void
  ): Promise<{ success: boolean; error?: string }> {
    try {
      // 确保安装目录存在
      await this.ensureDirectoryExists(this.nodePortablePath);
      
      const zipPath = path.join(this.nodePortablePath, 'nodejs.zip');
      
      // 下载Node.js
      progressCallback?.({
        stage: 'downloading',
        progress: 0,
        message: '开始下载Node.js...'
      });
      
      await this.downloadFile(this.downloadUrl, zipPath, (progress) => {
        progressCallback?.({
          stage: 'downloading',
          progress: Math.round(progress * 50), // 下载占50%进度
          message: `下载中... ${Math.round(progress * 100)}%`
        });
      });

      // 解压文件
      progressCallback?.({
        stage: 'extracting',
        progress: 50,
        message: '解压Node.js文件...'
      });
      
      await this.extractZip(zipPath, this.nodePortablePath);
      
      // 移动文件到正确位置
      await this.organizeNodeFiles();
      
      // 清理下载的zip文件
      if (fs.existsSync(zipPath)) {
        fs.unlinkSync(zipPath);
      }
      
      progressCallback?.({
        stage: 'configuring',
        progress: 90,
        message: '配置Node.js环境...'
      });
      
      // 验证安装
      const status = await this.checkPortableNode();
      if (!status.isInstalled) {
        throw new Error('安装验证失败');
      }
      
      progressCallback?.({
        stage: 'completed',
        progress: 100,
        message: 'Node.js安装完成！'
      });
      
      return { success: true };
    } catch (error: any) {
      progressCallback?.({
        stage: 'error',
        progress: 0,
        message: '安装失败',
        error: error.message
      });
      
      return {
        success: false,
        error: `安装Node.js时出错: ${error.message}`
      };
    }
  }

  /**
   * 为插件检查和安装依赖
   */
  public async checkAndInstallPluginDependencies(
    pluginPath: string,
    progressCallback?: (message: string, progress: number) => void
  ): Promise<{ success: boolean; error?: string; installedPackages?: string[] }> {
    try {
      const packageJsonPath = path.join(pluginPath, 'package.json');
      
      if (!fs.existsSync(packageJsonPath)) {
        return {
          success: true,
          error: '插件无package.json文件，跳过依赖检查'
        };
      }

      const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
      const dependencies = packageJson.dependencies || {};
      const nodeModulesPath = path.join(pluginPath, 'node_modules');
      
      // 检查是否需要安装依赖
      const missingDeps = [];
      for (const [depName, depVersion] of Object.entries(dependencies)) {
        const depPath = path.join(nodeModulesPath, depName);
        if (!fs.existsSync(depPath)) {
          missingDeps.push(depName);
        }
      }
      
      if (missingDeps.length === 0) {
        return {
          success: true,
          installedPackages: []
        };
      }
      
      progressCallback?.(`发现 ${missingDeps.length} 个缺失依赖，开始安装...`, 10);
      
      // 获取Node.js环境
      const nodeStatus = await this.checkNodeEnvironment();
      if (!nodeStatus.isInstalled) {
        throw new Error('Node.js环境未安装，无法安装依赖');
      }
      
      // 安装依赖
      const result = await this.runNpmInstall(pluginPath, nodeStatus, progressCallback);
      
      return {
        success: result.success,
        error: result.error,
        installedPackages: missingDeps
      };
    } catch (error: any) {
      return {
        success: false,
        error: `检查插件依赖时出错: ${error.message}`
      };
    }
  }

  /**
   * 运行npm install
   */
  private async runNpmInstall(
    pluginPath: string,
    nodeStatus: NodeEnvironmentStatus,
    progressCallback?: (message: string, progress: number) => void
  ): Promise<{ success: boolean; error?: string }> {
    return new Promise((resolve) => {
      let npmCommand: string;
      
      if (nodeStatus.isPortable) {
        npmCommand = path.join(this.nodePortablePath, 'npm.cmd');
      } else {
        npmCommand = 'npm';
      }
      
      const npmProcess = spawn(npmCommand, ['install'], {
        cwd: pluginPath,
        stdio: ['pipe', 'pipe', 'pipe'],
        shell: true
      });
      
      let output = '';
      let progress = 20;
      
      npmProcess.stdout?.on('data', (data) => {
        output += data.toString();
        progress = Math.min(progress + 5, 90);
        progressCallback?.(`安装依赖中... ${data.toString().trim()}`, progress);
      });
      
      npmProcess.stderr?.on('data', (data) => {
        output += data.toString();
        console.warn('npm install stderr:', data.toString());
      });
      
      npmProcess.on('close', (code) => {
        if (code === 0) {
          progressCallback?.('依赖安装完成！', 100);
          resolve({ success: true });
        } else {
          resolve({
            success: false,
            error: `npm install失败，退出码: ${code}\n输出: ${output}`
          });
        }
      });
      
      npmProcess.on('error', (error) => {
        resolve({
          success: false,
          error: `启动npm install失败: ${error.message}`
        });
      });
    });
  }

  /**
   * 下载文件
   */
  private async downloadFile(
    url: string,
    filePath: string,
    progressCallback?: (progress: number) => void
  ): Promise<void> {
    return new Promise((resolve, reject) => {
      const file = createWriteStream(filePath);
      
      https.get(url, (response) => {
        const totalSize = parseInt(response.headers['content-length'] || '0', 10);
        let downloadedSize = 0;
        
        response.on('data', (chunk) => {
          downloadedSize += chunk.length;
          if (totalSize > 0) {
            const progress = downloadedSize / totalSize;
            progressCallback?.(progress);
          }
        });
        
        response.pipe(file);
        
        file.on('finish', () => {
          file.close();
          resolve();
        });
        
        file.on('error', (error) => {
          fs.unlink(filePath, () => {}); // 删除部分下载的文件
          reject(error);
        });
      }).on('error', (error) => {
        reject(error);
      });
    });
  }

  /**
   * 解压ZIP文件
   */
  private async extractZip(zipPath: string, extractPath: string): Promise<void> {
    const extract = require('extract-zip');
    await extract(zipPath, { dir: extractPath });
  }

  /**
   * 整理Node.js文件结构
   */
  private async organizeNodeFiles(): Promise<void> {
    // 查找解压后的Node.js文件夹
    const files = fs.readdirSync(this.nodePortablePath);
    const nodeFolder = files.find(file => file.startsWith('node-v') && fs.statSync(path.join(this.nodePortablePath, file)).isDirectory());
    
    if (nodeFolder) {
      const sourcePath = path.join(this.nodePortablePath, nodeFolder);
      const sourceFiles = fs.readdirSync(sourcePath);
      
      // 移动所有文件到根目录
      for (const file of sourceFiles) {
        const srcFile = path.join(sourcePath, file);
        const destFile = path.join(this.nodePortablePath, file);
        
        if (fs.existsSync(destFile)) {
          // 如果目标文件已存在，先删除
          if (fs.statSync(destFile).isDirectory()) {
            fs.rmSync(destFile, { recursive: true, force: true });
          } else {
            fs.unlinkSync(destFile);
          }
        }
        
        fs.renameSync(srcFile, destFile);
      }
      
      // 删除空的源文件夹
      fs.rmdirSync(sourcePath);
    }
  }

  /**
   * 确保目录存在
   */
  private async ensureDirectoryExists(dirPath: string): Promise<void> {
    if (!fs.existsSync(dirPath)) {
      fs.mkdirSync(dirPath, { recursive: true });
    }
  }

  /**
   * 获取Node.js可执行文件路径
   */
  public getNodeExecutablePath(): string | null {
    const portableNodePath = path.join(this.nodePortablePath, 'node.exe');
    if (fs.existsSync(portableNodePath)) {
      return portableNodePath;
    }
    return null;
  }

  /**
   * 获取npm可执行文件路径
   */
  public getNpmExecutablePath(): string | null {
    const portableNpmPath = path.join(this.nodePortablePath, 'npm.cmd');
    if (fs.existsSync(portableNpmPath)) {
      return portableNpmPath;
    }
    return null;
  }

  /**
   * 检查插件依赖
   */
  public async checkPluginDependencies(pluginName: string): Promise<{
    hasNodeModules: boolean;
    missingDependencies: string[];
    packageJsonExists: boolean;
  }> {
    try {
      const pluginPath = path.join(process.cwd(), 'src', 'plugins', pluginName);
      const packageJsonPath = path.join(pluginPath, 'package.json');
      const nodeModulesPath = path.join(pluginPath, 'node_modules');
      
      const packageJsonExists = fs.existsSync(packageJsonPath);
      const hasNodeModules = fs.existsSync(nodeModulesPath);
      
      let missingDependencies: string[] = [];
      
      if (packageJsonExists) {
        const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
        const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
        
        if (hasNodeModules) {
          // 检查每个依赖是否存在
          for (const dep of Object.keys(dependencies)) {
            const depPath = path.join(nodeModulesPath, dep);
            if (!fs.existsSync(depPath)) {
              missingDependencies.push(dep);
            }
          }
        } else {
          // 如果没有node_modules，所有依赖都缺失
          missingDependencies = Object.keys(dependencies);
        }
      }
      
      return {
        hasNodeModules,
        missingDependencies,
        packageJsonExists
      };
    } catch (error) {
      console.error('检查插件依赖失败:', error);
      return {
        hasNodeModules: false,
        missingDependencies: [],
        packageJsonExists: false
      };
    }
  }

  /**
   * 安装插件依赖
   */
  public async installPluginDependencies(
    pluginName: string,
    onProgress?: (progress: { stage: string; message: string; progress: number }) => void
  ): Promise<void> {
    return new Promise((resolve, reject) => {
      try {
        const pluginPath = path.join(process.cwd(), 'src', 'plugins', pluginName);
        const packageJsonPath = path.join(pluginPath, 'package.json');
        
        if (!fs.existsSync(packageJsonPath)) {
          reject(new Error('插件没有package.json文件'));
          return;
        }
        
        // 获取npm路径
        const npmPath = this.getNpmExecutablePath();
        if (!npmPath) {
          reject(new Error('未找到npm，请先安装Node.js'));
          return;
        }
        
        onProgress?.({ stage: 'installing', message: '正在安装依赖...', progress: 0 });
        
        const { spawn } = require('child_process');
        const npmProcess = spawn(npmPath, ['install'], {
          cwd: pluginPath,
          stdio: ['pipe', 'pipe', 'pipe'],
          shell: true
        });
        
        let output = '';
        
        npmProcess.stdout.on('data', (data: Buffer) => {
          const text = data.toString();
          output += text;
          console.log('npm install output:', text);
          onProgress?.({ stage: 'installing', message: text.trim(), progress: 50 });
        });
        
        npmProcess.stderr.on('data', (data: Buffer) => {
          const text = data.toString();
          output += text;
          console.error('npm install error:', text);
        });
        
        npmProcess.on('close', (code: number) => {
          if (code === 0) {
            onProgress?.({ stage: 'completed', message: '依赖安装完成', progress: 100 });
            resolve();
          } else {
            const error = new Error(`npm install 失败，退出码: ${code}\n输出: ${output}`);
            onProgress?.({ stage: 'error', message: error.message, progress: 0 });
            reject(error);
          }
        });
        
        npmProcess.on('error', (error: Error) => {
          const errorMsg = `启动npm进程失败: ${error.message}`;
          onProgress?.({ stage: 'error', message: errorMsg, progress: 0 });
          reject(new Error(errorMsg));
        });
        
      } catch (error) {
        const errorMsg = `安装插件依赖失败: ${error instanceof Error ? error.message : String(error)}`;
        onProgress?.({ stage: 'error', message: errorMsg, progress: 0 });
        reject(new Error(errorMsg));
      }
    });
  }
}

export const nodeEnvironmentService = NodeEnvironmentService.getInstance();